/*
 * =====================================================================================
 *
 *       Filename:  mini_main.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  09/13/2012 02:40:53 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  baiyu (bekars), bekars@gmail.com
 *        Company:  BW
 *
 * =====================================================================================
 */

/**
 * 1. dnotify监控/data/nginx目录
 */ 

#include "mini_inc.h"
#include "mini_inotify.h"
#include "mini_tree.h"
#include "mini_dir.h"

#define EVENT_SIZE  (sizeof(struct inotify_event))
#define BUF_LEN     (1024 * (EVENT_SIZE + 16))

#define MINI_FILE_LEN       128
#define MINI_MAX_PATH_LEN   1024
#define MINI_CACHE_BASE     "/data/nginx/cache"

unsigned int malloc_count = 0;
unsigned int free_count = 0;
struct memrecord malloc_debug[MM_DEBUG_MAX];

mini_tree_node_t *rnode = NULL;
int fd = 0;

typedef struct mini_wd
{
    int wd;
    char pname[128];
} mini_wd_t, *mini_wd_p; 

int
mini_wd_compare(void *data, void *cmp)
{
    mini_wd_t *d = (mini_wd_t *)data;
    int *wd = (int *)cmp;

    if (d->wd == *wd) {
        return MINI_TREE_SAME;
    }
    return MINI_TREE_DIFF;
}

int
mini_wd_compare_path(void *data, void *cmp)
{
    mini_wd_t *d = (mini_wd_t *)data;
    char *p = (char *)cmp;

    if (!strcmp(d->pname, p)) {
        return MINI_TREE_SAME;
    }
    return MINI_TREE_DIFF;
}

void
mini_wd_show(void *data)
{
    mini_wd_t *d = (mini_wd_t *)data;
    printf("%s(%d)\n", d->pname, d->wd);
}

int
mini_wd_del(void *data)
{
    mini_wd_t *d = (mini_wd_t *)data;
    mini_inotify_rmwatch(fd, d->wd);
    return MINI_TREE_OK;
}

int
mini_wd_get_path(mini_tree_node_t *n, char *path, int pathlen)
{
    int i = 0;
    int len = 0;
    mini_wd_t *wdata = NULL;
    mini_tree_node_t *arr[MINI_TREE_MAX_DEEP] = { 0 };

    if (!n) return MINI_TREE_ERR;

    memset(path, 0, pathlen);
    strcpy(path, MINI_CACHE_BASE); 
    len += strlen(MINI_CACHE_BASE);

    do {
        arr[i++] = n;
        n = n->f;
    } while (n);

    for (--i; i >= 0; --i) {
        wdata = (mini_wd_t *)arr[i]->data;
        if ((len + strlen(wdata->pname)) >= pathlen) 
            return MINI_TREE_ERR;

        sprintf(path + len, "%s", wdata->pname);
        len += strlen(wdata->pname);
    }
    return len;
}

static int
mini_wd_add_file(const char *pathname, const struct stat *stat, int type)
{
    switch (type) {
        case FTW_F:
            switch (stat->st_mode & S_IFMT) {
                case S_IFREG:	
                    printf("WD: %s\n", pathname);		
                    break;
            }
            break;
 
        case FTW_D:
            mini_printf("WD: directory %s was created.\n", pathname);       
            break;

        default:
            break;
    }
    return 0;
}

static void
mini_quit_signal(int signo)
{
    (void)signo;
}

static void
mini_do_signal(void)
{
    signal(SIGINT, mini_quit_signal);
    signal(SIGTERM, mini_quit_signal);
    signal(SIGQUIT, mini_quit_signal);
    signal(SIGHUP, mini_quit_signal);
    signal(SIGCHLD, SIG_IGN);
}

int
main(int argc, char **argv)
{
    int ret;
    int len, index = 0;
    int wd;
    char buf[BUF_LEN];
    char path[MINI_MAX_PATH_LEN];
    char tmppath[MINI_MAX_PATH_LEN];
    struct inotify_event *event = NULL;
    mini_tree_node_t *fnode = NULL;
    mini_tree_node_t *cnode = NULL;
    mini_wd_t *wdata = NULL;
    fd_set rset;

//extern int mini_dir_main(int argc, char **argv);
//    mini_dir_main(argc, argv);

    mini_do_signal();

    fd = mini_inotify_init();
    wd = mini_inotify_addwatch(fd, MINI_CACHE_BASE);
    rnode = mini_tree_create_node(sizeof(mini_wd_t));
    wdata = (mini_wd_t *)rnode->data;
    wdata->wd = wd;
    strcpy(wdata->pname, "/");

    FD_ZERO(&rset);
    for (;;)
    {
        FD_SET(fd, &rset);
        if ((ret = select(fd + 1, &rset, NULL, NULL, NULL)) < 0) {
            if (errno == EINTR) {
                mini_printf("signal to exit.\n");
                break;
            } else {
                mini_error("select error");
            }
        }

        if (FD_ISSET(fd, &rset)) {
            index = 0;
            len = read(fd, buf, BUF_LEN);  
            while (index < len)
            {
                event = (struct inotify_event *)&buf[index];
                if (event->len)
                {
                    if (event->mask & IN_MOVED_TO) {
                        if (event->mask & IN_ISDIR) {
                            mini_printf("The directory %s was moved to.\n", event->name);       
                        }
                        else {
                            mini_printf("The file %s was moved to.\n", event->name);
                        }
                    }
                    else if (event->mask & IN_CREATE) {
                        if (event->mask & IN_ISDIR) {
                            mini_printf("The directory %s was created.\n", event->name);       

                            fnode = mini_tree_find(rnode, &event->wd, mini_wd_compare);
                            if (fnode) {
                                mini_wd_get_path(fnode, path, MINI_MAX_PATH_LEN);
                                sprintf(path + strlen(path), "%s", event->name);

                                wd = mini_inotify_addwatch(fd, path);
                                cnode = mini_tree_create_node(sizeof(mini_wd_t));
                                if (cnode) {
                                    wdata = (mini_wd_t *)cnode->data;
                                    wdata->wd = wd;
                                    sprintf(wdata->pname, "%s/", event->name);
                                    mini_tree_insert(fnode, cnode);

                                    mini_dir_list(path, mini_wd_add_file);
                                }
                            }
                        }
                        else {
                            mini_printf("The file %s was created.\n", event->name);
                        }
                    }
                    else if (event->mask & IN_DELETE) {
                        if (event->mask & IN_ISDIR) {
                            mini_printf("The directory %d %s was deleted.\n", event->wd, event->name);       
                            
                            fnode = mini_tree_find(rnode, &event->wd, mini_wd_compare);
                            if (fnode) {
                                sprintf(tmppath, "%s/", event->name);
                                cnode = mini_tree_find_child(fnode, tmppath, mini_wd_compare_path);
                                if (cnode) {
                                    mini_tree_free_tree(cnode);
                                }
                            }
                        }
                        else {
                            mini_printf("The file %s was deleted.\n", event->name);
                        }
                    }
                    else if (event->mask & IN_MODIFY) {
                        if (event->mask & IN_ISDIR) {
                            mini_printf("The directory %s was modified.\n", event->name);
                        }
                        else {
                            mini_printf("The file %s was modified.\n", event->name);
                        }
                    }
                }

                index += EVENT_SIZE + event->len;
            }
        }
    }

    mini_tree_dump(rnode, mini_wd_show, 0);

    mini_tree_list(rnode, mini_wd_del);
    mini_tree_free_tree(rnode);
    mini_inotify_exit(fd);

    dump_malloc_stats();

    exit(0);
}


